#!/usr/bin/perl

#------------------------------------------------------------#
# Program to bin the SS433 photometric data in all_sort.dat  #
# in various ways.                                           #
#                                                            #
# See binning.readme and the comments within this file for   #
# a description of the code				                     #
#                                             Bmort  29Mar07 #
#------------------------------------------------------------#

system("clear");

print "===================================================\n";
print "\tData binning for SS433 data\n";
print "\t(for help see binning.readme)\n";
print "===================================================\n";

# GET COMMAND ARGS FOR FILE NAMES
# ================================
$numArgs = $#ARGV + 1;
if ($numArgs != 2) {
    message("ERROR: Incorect number of command line args");
    messageLine();
    usage();
    exit(1);
}

$dataFileName = $ARGV[0];
$outFile = $ARGV[1];
message("Input data file = \"$dataFileName\"");
message("Output file root= \"$outFile\"");
messageLine();

# OPEN DATA FILE AND STORE IN ARRAY OF RAW DATA
use Cwd;
$dir = getcwd(); # Where am I?
open(DATA, $dataFileName);
@lines = <DATA>; # read data file into an array
close(DATA);

# EXTRACT RAW DATA INTO USEFUL ARRAYS
#====================================
$i=0;
$lskip = 0; # fix for blank lines
@ObsTime;
@ObsMag;
foreach $line (@lines) {
    if ($line =~ /^\s+/) { print "** "; $lskip++;}
    $line =~ m/^(\d+\.\d+|\d+|-\d+\.\d+|-\d+)\s+(\d+\.\d+|\d+|-\d+\.\d+|-\d+)/;
    $ObsTime[$i] = $1;
    $ObsMag[$i]  = $2;
    $i++;
}

# GET SOME INFO ON THE DATA
#==========================
$dataLength = $i-$lskip;
message("Data Length (# samples) = $dataLength");
$ObsTimeRange = $ObsTime[$dataLength-1]-$ObsTime[0];
message("Obs. time range ($ObsTime[0] to $ObsTime[$dataLength-1]) = $ObsTimeRange");
messageLine();

# GET BINNING PARAMETERS (FROM STDIN - USER PROMTEDED)
#=====================================================
$BinType = &promptUser("* Binning Type (1=simple, 2=adaptive,3=sequential), ",1);
#simple mode parameters
if ($BinType == 1) {
    #prompt user for inputs 
    messageLine();
    title_message("Simple Binning options:");
    $binLength = &promptUser("* Enter bin length (days), ", 365);
    $binOverlap = &promptUser("* Enter bin overlap (days), ",0);
    $binStartOffset = &promptUser("* Enter bin start offset (days), ",0);
    #print summary
    message();
    sub_message("Bin length  = $binLength");
    sub_message("Bin overlap = $binOverlap");
    sub_message("Bin start offset = $binStartOffset");
} 
#adaptive mode parameters
elsif ($BinType == 2) { # adaptive
}
elsif ($BinType == 3) { # sequential
    messageLine();
    title_message("Sequential Binning options:");
    $binLength = &promptUser("* Enter bin length (days), ",
			     int $ObsTimeRange/5);
    $binStartOffset = &promptUser("* Enter bin start offset (days), ",0);
    #print summary
    message();
    sub_message("Bin length  = $binLength");
    sub_message("Bin start offset = $binStartOffset");
}
else {
    message("ERROR: Unrecognised binning type!");
    exit(2);
}

if ($BinType == 1) {
#check for some simple errors in imputs
    if ($binOverlap >= $binLength) {
	messageLine();
	message("ERROR: Bin overlap longer than bin length, check options!");
	exit(3);
    }
}



#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# SIMPLE BINNING <STARTS HERE>
# ----------------------------------------------------------------------------
if ($BinType == 1) {
    
    # Get the number of bins
    $range = $ObsTimeRange - $binStartOffset + 1;
    $overlap = $binOverlap;
    $fractNumBins = ($range-$overlap) / ($binLength-$overlap);
    $intNumBins = int $fractNumBins;
    
    messageLine();
    message("Fractional number of bins  = $fractNumBins");   
    message("Whole number of bins       = $intNumBins");   
    
    if ($intNumBins < 1) {
    	message();
    	message("ERROR: No full length bins fit in the data set, check options!");
    	exit(3);
    }
    messageLine();

    # Generate ideal bin edges
    @binFileNames;
    @binStartTimes;
    @binEndTimes;
    $iBin = 0;
    $binStartTimes[$iBin] = $ObsTime[0] + $binStartOffset;
    $binEndTimes[$iBin]   = $binStartTimes[$iBin] + ($binLength);
    for ($iBin=1;$iBin<$intNumBins;$iBin++) {
    	$binStartTimes[$iBin] = $binEndTimes[$iBin-1]+1-$binOverlap;
    	$binEndTimes[$iBin]   = $binStartTimes[$iBin]+($binLength);
    }
    
    for ($iBin=0;$iBin<$intNumBins;$iBin++) {
	$binFileNames[$iBin] = "$outFile-bin".$iBin.".dat";
    }
    for ($iBin=0;$iBin<$intNumBins;$iBin++) {
	my $tmpLen = 0.0;
    	$tmpLen = $binEndTimes[$iBin]-$binStartTimes[$iBin];
    	title_message("Bin-$iBin:");
    	sub_message("fileName = $binFileNames[$iBin]");
    	sub_message("time     = $binStartTimes[$iBin] to $binEndTimes[$iBin]");
    	sub_message("length   = $tmpLen");
    }


    # Find actual bin edges based on ideal boundries
    @dataBinStartTimes;
    @dataBinEndTimes;  
    
    # find the real data times closest to @BinStartTimes
    for ($iBin=0;$iBin<$intNumBins;$iBin++) {
    	$tmpBinStartTimeLower = 0.0;
	    $tmpBinStartTimeUpper = 0.0;
    	$diffLower = 0.0;
    	$diffUpper = 0.0;
    	$tmpBinStartIndexLower = 0;
	    $tmpBinStartIndexUpper = 0;
	    for ($i=0;$i<($dataLength);$i++) {
	        if ($ObsTime[$i] <= $binStartTimes[$iBin]) {
	           	$tmpBinStartTimeLower  = $ObsTime[$i];
	           	$tmpBinStartTimeUpper  = $ObsTime[$i+1];
	           	$tmpBinStartIndexLower = $i;
	           	$tmpBinStartIndexUpper = $i+1;
	        }
	    }
	    $diffLower = $binStartTimes[$iBin]-$tmpBinStartTimeLower;
	    $diffUpper = $tmpBinStartTimeUpper -$binStartTimes[$iBin];

	    if ($diffLower < $diffUpper) {
	        $dataBinStartTimes[$iBin] = $tmpBinStartTimeLower;
	    } else {
	        $dataBinStartTimes[$iBin] = $tmpBinStartTimeUpper;
	    }
    }

    # find the read data times closest to @BinEndTimes
    for ($iBin=0;$iBin<$intNumBins;$iBin++) {
    	$tmpBinEndTimeLower = 0.0;
	    $tmpBinEndTimeUpper = 0.0;
	    $diffLower = 0.0;
	    $diffUpper = 0.0;
	    $tmpBinEndIndexLower = 0;
	    $tmpBinEndIndexUpper = 0;
	    for ($i=0;$i<($dataLength);$i++) {
	        if ($ObsTime[$i] <= $binEndTimes[$iBin]) {
	        	$tmpBinEndTimeLower  = $ObsTime[$i];
	            $tmpBinEndTimeUpper  = $ObsTime[$i+1];
	        	$tmpBinEndIndexLower = $i;
	        	$tmpBinEndIndexUpper = $i+1;
	        }
	    }
	    $diffLower = $binEndTimes[$iBin]-$tmpBinEndTimeLower;
	    $diffUpper = $tmpBinEndTimeUpper -$binEndTimes[$iBin];


	    if (abs($diffLower) < abs($diffUpper)) {
	        $dataBinEndTimes[$iBin] = $tmpBinEndTimeLower;
	    } else {
	        $dataBinEndTimes[$iBin] = $tmpBinEndTimeUpper;
	    }
    }


    messageLine();
    for ($iBin=0;$iBin<$intNumBins;$iBin++) {
    	my $tmpLen = 0.0;
    	$tmpLen = $dataBinEndTimes[$iBin]-$dataBinStartTimes[$iBin];
    	message("Bin-$iBin");
    	sub_message("startTime:  $dataBinStartTimes[$iBin]");
    	sub_message("endTime:    $dataBinEndTimes[$iBin]");
    	sub_message("length :    $tmpLen");
    }

    # write the bin data
    @NbinPoints;
    for ($iBin=0;$iBin<$intNumBins;$iBin++) {
	    title_message("Writing $binFileNames[$iBin]");
    	open(OUT_BIN, ">$binFileNames[$iBin]");
    	$NbinPoints[$iBin] = 0;
	    for ($i=0;$i<($dataLength);$i++) {
	        if($ObsTime[$i] >= $dataBinStartTimes[$iBin] &&
	           $ObsTime[$i] <= $dataBinEndTimes[$iBin]) {
    	    	print OUT_BIN "$ObsTime[$i]  $ObsMag[$i]\n";
	        	$NbinPoints[$iBin]++;
	        }
	    }
	    print STDERR "- bin: $iBin  Npoints: $NbinPoints[$iBin]\n";
	    close(OUT_BIN);
    }
    messageLine();
}
messageLine();

# <END OF SIMPLE BINNING>
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++





















#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# ADAPTIVE BINNING <STARTS HERE>
# -----------------------------------------------------------------------------
if ($BinType == 2) 
{ 
    @timeDifference;
    # get difference array
    for ($i=0;$i<($dataLength-1);$i++) {
	$timeDifference[$i] = $ObsTime[$i+1] - $ObsTime[$i];
    }
    # get average diff
    $diffSum = 0.0;
    for ($i=0;$i<($dataLength-1);$i++) {
	$diffSum += $timeDifference[$i];
    }
    $aveDiff = $diffSum/($dataLength-1);
    @offsetDifference;
    for ($i=0;$i<($dataLength-1);$i++) {
	$offsetDifference[$i] = $timeDifference[$i] - $aveDiff;
	$offsetFactor[$i] = $timeDifference[$i]/$aveDiff;
    }
    message("average difference = $aveDiff");
    
    # OPTIONS
    # get first guess at bin boundaries from the offsetFactor >
    # specified min offset factor (default 10)
    messageLine();
    message("The min. offset factor is the number of time the average");
    message("time difference btween samples that is seen as acceptable");
    message("for continuous measurement");
    $minOffset = &promptUser("* Enter min offset factor: ",
			     10);
    message("The min. bin length is used to determine what bins");
    message("found using the above offset criteria should be considered as");
    message("useful bins");
    $minBinLength = &promptUser("* Enter min bin length (days): ",
				200);
    $minBinSamples = &promptUser("* Enter min bin samples (# data samples): ",
				 10);
#   $maxBinGap     = &promptUser("* Enter max acceptable bin gap (days): ",
#				 100);
    
    messageLine();
    message("Selection Factors:");
    sub_message("Min offset factor          = $minOffset");
    sub_message("Min bin time length (days) = $minBinLength");
    sub_message("Min data samples per bin   = $minBinSamples");
#    sub_message("Max bin gap                = $maxBinGap");
    
    # GUESS AT BIN EDGES (END TIMES FOR BINS ARE CALCULATED)
    @guessEndTime;
    @guessEndIndex;
    @guessStartIndex;
    @guessStartTime;
    $guessStartIndex[0] = 0;
    $guessStartTime[0] = $ObsTime[0];
    $kBin = 0;
    for ($i=0;$i<($dataLength-1);$i++) {
	if ($offsetFactor[$i] >= $minOffset) {
	    $guessEndTime[$kBin] = $ObsTime[$i];
	    $guessEndIndex[$kBin] = $i;
	    $guessStartIndex[$kBin+1] = $i+1;
	    $guessStartTime[$kBin+1] = $ObsTime[$i+1];
	    $kBin++;
	}
    }
    $guessEndTime[$kBin] = $ObsTime[$dataLength-1];
    $guessEndIndex[$kBin] = $dataLength-1;

    messageLine();
    $nBinEdgeGuess = $kBin;
    message("Number of bins found = $nBinEdgeGuess");

    # BIN TESTING PARAMETERS (TIME AND INDEX DIFFERENCES)
    # ------------------------------------------
    # => Tdiff[bin] array for the time difference between
    #      start and end of a bin
    # => GapTime[bin] array for the time difference between
    #      adjacent bins
    # => Sdiff[bin] array for the index (data points) 
    #      differences between start and end of a bin
    for ($i=0;$i<=$nBinEdgeGuess;$i++) {
	$Tdiff[$i]   = $guessEndTime[$i] - $guessStartTime[$i]; 
	$Sdiff[$i]   = $guessEndIndex[$i] - $guessStartIndex[$i]+1;
	if ($i < $nBinEdgeGuess) {
	    $GapTime[$i] = $guessStartTime[$i+1] - $guessEndTime[$i];
	} else {
	    $GapTime[$i] = 0.0;
	}
    }

    @passedBins;
    $pBin = 0;
#messageLine();
    for ($z=0;$z<=$nBinEdgeGuess;$z++) {
	#printf ("%d\t%.1f\t %d",$z,$Tdiff[$z],$Sdiff[$z]);
	if ( ($Tdiff[$z] >= $minBinLength) 
	     && ($Sdiff[$z] >= $minBinSamples) ) {
	    $passedBins[$pBin] = $z;
	    $pBin++;
	    #   print "\txx\n";
	} else {
	    #  print "\n";
	}
    }
    $nBins = $pBin;
    message("Number of bins passed selection = $nBins");
    messageLine();


    for ($p=0;$p<$pBin;$p++) {
	#print "$passedBins[$p]\n";
	$StartIndex[$p] = $guessStartIndex[$passedBins[$p]];
	$StartTime[$p]  = $guessStartTime[$passedBins[$p]];
	$EndIndex[$p]   = $guessEndIndex[$passedBins[$p]];
	$EndTime[$p]    = $guessEndTime[$passedBins[$p]];
    }

    for ($iBin=0;$iBin<$pBin;$iBin++) {
	$binFileNames[$iBin] = "$outFile-bin".$iBin.".dat";
    }

    for ($iBin=0;$iBin<$pBin;$iBin++) {
	my $tmpLen = 0.0;
	$tmpLen = $EndTime[$iBin]-$StartTime[$iBin];
	title_message("Bin-$iBin:  ($passedBins[$iBin])");
	sub_message("fileName = $binFileNames[$iBin]");
	sub_message("time     = $StartTime[$iBin] to $EndTime[$iBin]");
	sub_message("length :    $tmpLen");
    }
    messageLine();


# (ADAPTIVE BINNING) OUTPUT TO FILE

    # DIFFERENCES (BETWEEN INDIVIDAL DATA POINTS)
    # file containing the differences between data points
    # this is expressed as absolute time difference, offset from the
    # average differnce and the offset factor from the average (ie.
    # the time difference / mean time difference)
    # <DATA POINT INDEX> <TIME DIFFERENCE> <TIME OFFSET> <OFFSET FACTOR>
    title_message("writing $outFile.diffs");
    open(OUT_DIFFS,">$outFile.diffs");
    for ($i=0;$i<($dataLength-1);$i++) {
	print OUT_DIFFS "$i $ObsTime[$i]\t$timeDifference[$i]\t";
	print OUT_DIFFS "$offsetDifference[$i] $offsetFactor[$i]\n";
    }
    close(OUT_DIFFS);

    # GUESS EDGES <<< *.guessEdges >>>
    # ---------------------------------------------------------
    # based on the offset factor this file contains a list of the 
    # bins selected.
    # <bin> <start index> <start time> <end index> <end time>
    title_message("writing $outFile.guessEdges");
    open(OUT_EDGE,">$outFile.guessEdges");
    for ($i=0;$i<=($nBinEdgeGuess);$i++) {
	print OUT_EDGE "$i\t";
	print OUT_EDGE "$guessStartIndex[$i]\t";
	print OUT_EDGE "$guessStartTime[$i]\t";
	print OUT_EDGE "$guessEndIndex[$i]\t";
	print OUT_EDGE "$guessEndTime[$i]\t";
	print OUT_EDGE "16\t";
	print OUT_EDGE "\n";
    }
    close(OUT_EDGE);

    # BIN TESTS <<< *.binTests >>>
    # ---------------------------------------------------------
    # <bin> <Time diff end-start> <index diff> <gap for bin to the next>
    title_message("writing $outFile.binTests");
    open(OUT_EDGE,">$outFile.binTests");
    for ($i=0;$i<=($nBinEdgeGuess);$i++) {
	print OUT_EDGE "$i\t";
	printf OUT_EDGE ("%.1f\t",$Tdiff[$i]);
	print OUT_EDGE "$Sdiff[$i]\t";
	printf OUT_EDGE ("%.1f\t",$GapTime[$i]);
	print OUT_EDGE "\n";
    }
    close(OUT_EDGE);


    
    # EDGE GUESSES <<< *.edges >>>
    # ---------------------------------------------------------
    # final bin selection based on selection parameters this file 
    # constains a list of the final bins selected
    # <bin> <start index> <start time> <end index> <end time>
    title_message("writing $outFile.edges");
    open(OUT_EDGE,">$outFile.edges");
    for ($i=0;$i<($nBins);$i++) {
	print OUT_EDGE "$i\t";
	print OUT_EDGE "$passedBins[$i]\t";
	print OUT_EDGE "$StartIndex[$i]\t";
	print OUT_EDGE "$StartTime[$i]\t";
	print OUT_EDGE "$EndIndex[$i]\t";
	print OUT_EDGE "$EndTime[$i]\t";
	print OUT_EDGE "17\t";
	print OUT_EDGE "\n";
    }
    close(OUT_EDGE);

    # BIN DATA FILES
    # this is where the actual bin data files are written out
    # <TIME OF OBSERVATION> <DATA MAGNITUDE> <DATA INDEX>
    messageLine();
    @NbinPoints;
    for ($iBin=0;$iBin<$nBins;$iBin++) {
	title_message("Writing $binFileNames[$iBin]");
	open(OUT_BIN, ">$binFileNames[$iBin]");
	#print STDOUT "$passedBins[$iBin]\n";
	$NbinPoints[$iBin] = 0;
	for ($i=0;$i<($dataLength);$i++) {
	    if($ObsTime[$i] >= $StartTime[$iBin] &&
	       $ObsTime[$i] <= $EndTime[$iBin]) {
		print OUT_BIN "$ObsTime[$i]  $ObsMag[$i]\n";
		$NbinPoints[$iBin]++;
	    }
	}
	print STDERR "- (bin: $iBin  Npoints: $NbinPoints[$iBin])\n";
	#message("done!");
	close(OUT_BIN);
    }
    messageLine();
} # $BinType == 2 # END OF ADAPTIVE BINNING OUTPUT #
# <END OF ADAPTIVE BINNING>
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++






















#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# SEQUENTIAL BINNING <STARTS HERE>
# -------------------------------------------------------------------------------
if ($BinType == 3) 
{ 
    print "TT: $binLength\n";
    print "TT: $binStartOffset\n";
    messageLine();
    $i=0;
    $iBIN = 0;
    $oldStart = $ObsTime[$i];
    @binEndTime;
    @binEndIndex;
    $binStartTime[0]=$ObsTime[0];
    $binStartIndex[0]=0;
    while ($i<$dataLength) {
	print "$i $ObsTime[$i] $ObsMag[$i]";
	if ($ObsTime[$i] > $oldStart + $binLength) {
	    $yy = $oldStart + $binLength;
	    $binFileNames[$iBIN] = "$outFile-bin".$iBIN.".dat";
	    print "   <--  BIN-$iBIN [$yy] ($binLength) <$binFileNames[$iBIN]>";
	    $binEndTime[$iBIN] = $ObsTime[$i]; 
	    $binEndIndex[$iBIN] = $i; 
	    $binStartTime[$iBIN+1] = $ObsTime[$i+1];
	    $binStartIndex[$iBIN+1] = $i+1; 
	    $iBIN++;
	    $oldStart = $ObsTime[$i+1];
	}
	print "\n";
	$i++;
    }

    messageLine();
    $nBins = $iBIN;
    for ($i=0;$i<$iBIN;$i++) {
	$idiff = $binEndIndex[$i]-$binStartIndex[$i]+1;
	$tdiff = $binEndTime[$i]-$binStartTime[$i];
	title_message("$binFileNames[$i]");
	print "- bin($i)\t|\t";
	print "($binStartIndex[$i])$binStartTime[$i]\t-> ";
	print "($binEndIndex[$i])$binEndTime[$i] \t| ";
	print "$idiff \t $tdiff";
	print "\n";
	open(OUT_BIN,">$binFileNames[$i]");
	$NbinPoints[$i] = 0;
	for ($j=0;$j<($dataLength);$j++) {
	    if($ObsTime[$j] >= $binStartTime[$i] &&
	       $ObsTime[$j] <= $binEndTime[$i]) {
		print OUT_BIN "$ObsTime[$j]  $ObsMag[$j]\n";
		$NbinPoints[$i]++;
	    }
	}
	print STDERR "- (bin: $i  Npoints: $NbinPoints[$i])\n";
	close(OUT_BIN);


	messageLine();
    }
    
    messageLine();
}































#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# COMMON OUTPUTS
#-----------------------------------------------------------------------------
# this includes, writing the indata back to a file, writing an info file,
# writing a summary file
# ----------------------------------------------------------------------------

# write the *INPUT DATA* back to file (for checking)
title_message("Writing $outFile.indata");
open(OUT_INDATA, ">$outFile.indata");
for ($i=0;$i<($dataLength);$i++) {
    print OUT_INDATA "$ObsTime[$i]\t $ObsMag[$i] \t $i\n";
}
close(OUT_INDATA);



# write the *INFO FILE* on data and binning
title_message("Writing $outFile.info");
open(OUT_INFO, ">$outFile.info");
open(OUT_INFO2, ">$outFile.info2");
# == common stuff (directory, output file name, data file neame, range of data etc)
print OUT_INFO "RUNDIR      =        $dir\n";
print OUT_INFO "OUTFILE     =        $dataFileName\n";
print OUT_INFO "DATAFILE    =        $outFile\n";
print OUT_INFO "DATALENGTH  =        $dataLength\n";
print OUT_INFO "OBS_T_RANGE =        $ObsTimeRange\n";

print OUT_INFO2 "-1 $outFile.indata $ObsTime[0] $ObsTime[$dataLength-1]\n";
# == simple binning specific info
if ($BinType == 1) {
    print OUT_INFO "BINTYPE     =        Simple binning\n";
    print OUT_INFO "LENGTH      =        $binLength\n";
    print OUT_INFO "OVERLAP     =        $binOverlap\n";
    print OUT_INFO "OFFSET      =        $binStartOffset\n";
    print OUT_INFO "FRACBINS    =        $fractNumBins\n";
    print OUT_INFO "INTBINS     =        $intNumBins\n";
    print OUT_INFO "TOT_OVERLAP =        $overlaps\n";
    
    for ($iBin=0;$iBin<$intNumBins;$iBin++) {
	my $tmpLen = 0.0;
    	$tmpLen = $dataBinEndTimes[$iBin]-$dataBinStartTimes[$iBin];
    	print OUT_INFO "\n";
    	print OUT_INFO "#BIN        =        Bin-$iBin:\n";
    	print OUT_INFO "FILENAME    =        $binFileNames[$iBin]\n";
    	print OUT_INFO "START_TIME  =        $dataBinStartTimes[$iBin]\n";
    	print OUT_INFO "END_TIME    =        $dataBinEndTimes[$iBin]\n";
    	print OUT_INFO "BIN_LENGTH  =        $tmpLen\n";
#    	print OUT_INFO2 "$iBin $binFileNames[$iBin] $dataBinStartTimes[$iBin] $dataBinEndTimes[$iBin] $NbinPoints[$iBin]\n";
    	print OUT_INFO2 "$iBin $binFileNames[$iBin] $binStartTimes[$iBin] $binEndTimes[$iBin] $NbinPoints[$iBin]\n";
    }
}
# == adapitive binning specific info
if ($BinType == 2) {
    print OUT_INFO "BINTYPE     =        Adaptive\n";
    print OUT_INFO "OFFSET_FACT =        $minOffset\n";
    print OUT_INFO "MIN_BIN_LEN =        $minBinLength\n";
    print OUT_INFO "MIN_BIN_DAT =        $minBinSamples\n";
    #print OUT_INFO "MAX_GAP     =        $maxBinGap\n";
    print OUT_INFO "BINS_GUESS  =        $nBinEdgeGuess\n";
    print OUT_INFO "NUM BINS    =        $nBins\n";
    print OUT_INFO "BIN GUESS   =        #################\n";
    for ($iBin=0;$iBin<$nBinEdgeGuess;$iBin++) {
	print OUT_INFO "\n";
	print OUT_INFO "#BIN        =        bin-$iBin\n";
	print OUT_INFO "START_TIME  =        $guessStartTime[$iBin]\n";
	print OUT_INFO "END_TIME    =        $guessEndTime[$iBin]\n";
	print OUT_INFO "TIME_LENGTH =        $Tdiff[$iBin]\n";
	print OUT_INFO "INDEX_LENGTH=        $Sdiff[$iBin]\n";
	print OUT_INFO "GAP AFTER   =        $GapTime[$iBin]\n";
    }
    print OUT_INFO "PASSED BINS =        #################\n";
    for ($iBin=0;$iBin<$nBins;$iBin++) {
	my $tmpLen = 0.0;
	$tmpLen = $EndTime[$iBin]-$StartTime[$iBin];
	my $tmpILen = 0.0;
	$tmpILen = $EndIndex[$iBin]-$StartIndex[$iBin]+1;
	print OUT_INFO "\n";
	print OUT_INFO "#BIN        =        Bin-$iBin\n";
	print OUT_INFO "BIN_GUESS # =        $passedBins[$iBin]\n";
	print OUT_INFO "FILENAME    =        $binFileNames[$iBin]\n";
	print OUT_INFO "START_TIME  =        $StartTime[$iBin]\n";
	print OUT_INFO "END_TIME    =        $EndTime[$iBin]\n";
	print OUT_INFO "TIME_LENGTH =        $tmpLen\n";
	print OUT_INFO "INDEX_LENGTH=        $tmpILen\n";
  	print OUT_INFO2 "$iBin $binFileNames[$iBin] $StartTime[$iBin] $EndTime[$iBin] $NbinPoints[$iBin]\n";
    }
}
# == sequential binning specific info
if ($BinType == 3) {
    print OUT_INFO "BINTYPE     =        Sequential\n";
    print OUT_INFO "LENGTH      =        $binLength\n";
    print OUT_INFO "OFFSET      =        $binStartOffset\n";
    print OUT_INFO "NUM BINS    =        $nBins\n";
    
    for ($iBin=0;$iBin<$nBins;$iBin++) {
	my $tmpLen = 0.0;
	$tmpLen = $binEndTime[$iBin]-$binStartTime[$iBin];
	my $tmpILen = 0.0;
	$tmpILen = $binEndIndex[$iBin]-$binStartIndex[$iBin]+1;
	print OUT_INFO "\n";
	print OUT_INFO "#BIN        =        Bin-$iBin\n";
	print OUT_INFO "BIN_GUESS # =        $passedBins[$iBin]\n";
	print OUT_INFO "FILENAME    =        $binFileNames[$iBin]\n";
	print OUT_INFO "START_TIME  =        $binStartTime[$iBin]\n";
	print OUT_INFO "END_TIME    =        $binEndTime[$iBin]\n";
	print OUT_INFO "TIME_LENGTH =        $tmpLen\n";
	print OUT_INFO "INDEX_LENGTH=        $tmpILen\n";
  	print OUT_INFO2 "$iBin $binFileNames[$iBin] $binStartTime[$iBin] $binEndTime[$iBin]  $NbinPoints[$iBin]\n";
    }
}


close(OUT_INFO);
close(OUT_INFO2);
messageLine();


# write a summary file with the input data and bin start/end flags
if ($BinType == 1) {
    $iBin=0;
    title_message("Writing $outFile.summary");
    open(OUT_SUMMARY, ">$outFile.summary");
    for ($i=0;$i<($dataLength);$i++) {
	if ($ObsTime[$i] == $dataBinStartTimes[$iBin]) {
	    print OUT_SUMMARY "$ObsTime[$i]\t $ObsMag[$i]   <== START ($iBin)\n";
	}
	if ($ObsTime[$i] == $dataBinEndTimes[$iBin]) {
	    print OUT_SUMMARY "$ObsTime[$i]\t $ObsMag[$i]   <== END ($iBin)";
	    $iBin++;
	    if ($ObsTime[$i] == $dataBinStartTimes[$iBin]) {
		print OUT_SUMMARY " + START ($iBin)";
	    }
	    print OUT_SUMMARY "\n";
	}
	else {
	    print OUT_SUMMARY "$ObsTime[$i]\t $ObsMag[$i]\n";
	}
    }
    close(OUT_SUMMARY);
    messageLine();
}



# write a summary file with the input data and bin start/end flags
title_message("Writing $outFile.plotinfo");
open(OUT_PLOT, ">$outFile.plotinfo");
$nB = 0;
if ($BinType == 1) {
    $nB = $intNumBins;
} else {
    $nB = $nBins;
}
for ($i=0;$i<($nB);$i++) {
    print OUT_PLOT "$i\t";
    print OUT_PLOT "$StartIndex[$i]\t";
    print OUT_PLOT "$StartTime[$i]\t";
    print OUT_PLOT "$EndIndex[$i]\t";
    print OUT_PLOT "$EndTime[$i]\t";
    print OUT_PLOT "\n";
}

close(OUT_PLOT);
messageLine();










####################################################################################
# SUBROUTINES
# 1. usage()
# 2. message()
# 3. messageLine()
# 4. sub_message()
# 5. title_message()
# 6. promptUser()
####################################################################################

sub usage()
{
    print "-\n";
    print "- USAGE: []\$ perl dataBinning.pl [DATAFILENAME] [OUTNAME_ROOT]\n";
    print "-\n";
}

sub message {
    my $messageString = shift;
    print "- $messageString\n";
}

sub messageLine {
    print "---------------------------------------------------\n";
}


sub sub_message {
    my $messageString = shift;
    print "-   $messageString\n";
}

sub title_message {
    my $messageString = shift;
    print "= $messageString\n";
}


sub promptUser {
    
    #-------------------------------------------------------------------#
    #  two possible input arguments - $promptString, and $defaultValue  #
    #  make the input arguments local variables.                        #
    #-------------------------------------------------------------------#
    
    local($promptString,$defaultValue) = @_;
    
    #-------------------------------------------------------------------#
    #  if there is a default value, use the first print statement; if   #
    #  no default is provided, print the second string.                 #
    #-------------------------------------------------------------------#
    
    
    if ($defaultValue || $defaultValue == 0) {
	print $promptString, "[", $defaultValue, "]: ";
    } else {
	print $promptString, ": ";
    }

    $| = 1;               # force a flush after our print
    $_ = <STDIN>;         # get the input from STDIN (presumably the keyboard)


    #------------------------------------------------------------------#
    # remove the newline character from the end of the input the user  #
    # gave us.                                                         #
    #------------------------------------------------------------------#

    chomp;

    #-----------------------------------------------------------------#
    #  if we had a $default value, and the user gave us input, then   #
    #  return the input; if we had a default, and they gave us no     #
    #  no input, return the $defaultValue.                            #
    #                                                                 # 
    #  if we did not have a default value, then just return whatever  #
    #  the user gave us.  if they just hit the <enter> key,           #
    #  the calling routine will have to deal with that.               #
    #-----------------------------------------------------------------#

    if ("$defaultValue" || $defaultValue == 0) {
	return $_ ? $_ : $defaultValue;    # return $_ if it has a value
    } else {
	return $_;
    }
}


